package com.ibm.framework.uts.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author <a href="mailto:ljw79618@gmail.com">L.J.W</a>
 */

public abstract class ExceptionUtils {

    /**
     * 字符串常量数组
     */
    private static final String[] CAUSE_METHOD_NAMES = { "getCause", "getNextException", "getTargetException",
            "getException", "getSourceException", "getRootCause", "getCausedByException", "getNested",
            "getLinkedException", "getNestedException", "getLinkedCause", "getThrowable", };

    /**
     * 获取原始异常
     * 
     * @param throwable 异常原因
     * @return 根异常
     */
    public static Throwable getRootCause(Throwable throwable) {
        List<Throwable> list = getThrowableList(throwable);
        return list.get(list.size() - 1);
    }

    /**
     * 获取异常列表
     * 
     * @param throwable 异常原因
     * @return 异常列表
     */
    public static List<Throwable> getThrowableList(Throwable throwable) {
        List<Throwable> list = new ArrayList<Throwable>();
        while (list.contains(throwable) == false) {
            list.add(throwable);
            throwable = ExceptionUtils.getCause(throwable);
        }
        return list;
    }

    /**
     * 获取异常
     * 
     * @param throwable 异常
     * @return 异常原因
     */
    public static Throwable getCause(Throwable throwable) {
        return getCause(throwable, CAUSE_METHOD_NAMES);
    }

    /**
     * 根据多个方法名获取异常
     * 
     * @param throwable 异常
     * @param methodNames 异常现场方法名
     * @return 异常原因
     */
    public static Throwable getCause(Throwable throwable, String[] methodNames) {
        if (throwable == null) {
            return null;
        }

        if (methodNames == null) {
            methodNames = CAUSE_METHOD_NAMES;
        }

        for (String methodName : methodNames) {
            if (methodName != null) {
                Throwable cause = getCauseUsingMethodName(throwable, methodName);
                if (cause != null) {
                    return cause;
                }
            }
        }

        return null;
    }

    /**
     * 根据方法名获取异常
     * 
     * @param throwable 异常原因
     * @param methodName 异常现场
     * @return 异常
     */
    private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) {
        Method method = null;
        try {
            method = throwable.getClass().getMethod(methodName);
        } catch (NoSuchMethodException ignored) {
            ignored.toString();
        } catch (SecurityException ignored) {
            ignored.toString();
        }

        if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) {
            try {
                return (Throwable) method.invoke(throwable);
            } catch (IllegalAccessException ignored) {
                ignored.toString();
            } catch (IllegalArgumentException ignored) {
                ignored.toString();
            } catch (InvocationTargetException ignored) {
                ignored.toString();
            }
        }
        return null;
    }

}
